(define (make-table)
  (let ((local-table (list '*table*)))
    (define (generic-lookup op init key-list)
      (define (iter table keys)
        (cond ((null? table) #f)
              ((null? keys) table)
              (else
               (let ((subtable (assoc (car keys) (cdr table))))
                 (if subtable
                     (iter subtable (cdr keys))
                     (iter (op (car keys) table)
                           (cdr keys)))))))
      (if (null? key-list)
          (error "need at least one key")
          (iter init key-list)))
    (define (lookup key-list)
      (generic-lookup (lambda (key table) '())
                      local-table
                      key-list))
    (define (insert! key-list value)
      (define (create-new key table)
        (let ((new-rear (cons (list key)
                              (cdr table))))
          (set-cdr! table new-rear)
          (car new-rear)))
      (set-cdr! (generic-lookup create-new local-table key-list)
                value)
      'ok)

    (define (print) 
      (define (indent tabs)
        (if (> tabs 0)
            (begin (display "    ")
                   (indent (- tabs 1)))))
  
      (define (print-record rec level) 
        (indent level) 
        (display (car rec)) 
        (display ": ") 
        (if (list? rec) 
            (begin (newline) 
                   (print-table rec (+ 1 level))) 
            (begin (display (cdr rec)) 
                   (newline)))) 
              
      (define (print-table table level) 
        (if (null? (cdr table)) 
            (begin (display "-no entries-") 
                   (newline)) 
            (for-each (lambda (record) 
                        (print-record record level)) 
                      (cdr table)))) 
  
      (print-table local-table 0))
    
    (define (dispatch m)
      (cond ((eq? m 'lookup-proc) lookup)
            ((eq? m 'insert-proc!) insert!)
            ((eq? m 'print) print)
            (else (error "Unknown operation -- TABLE" m))))
    dispatch))

;(define operation (make-table))
;(define get (operation 'lookup-proc))
;(define put (operation 'insert-proc!))

;(get '(make rational))
;(put '(make rational) (lambda (n d) (list n d)))
;(get '(make rational))
;(display ((get '(make rational)) 1 4))

(define (make-table-general)
  (let ((local-table (list '*table*)))
    (define (general-lookup op init seq)
      ;;the result of this proc is depended on the op
      ;;for lookup or insert!
      (define (iter res key-list)
        (if (null? key-list)
            res
            (iter (op (car key-list) res)
                  (cdr key-list))))
      (iter init seq))
    
    (define (lookup key-list)
      (define (sub-lookup key records)
        (if records
            (let ((record (assoc key records)))
              (if record
                  (cdr record)
                  false))
            false))
      (general-lookup sub-lookup (cdr local-table) key-list))

    (define (insert! key-list value)
      (define (sub-insert key table)
        (let ((record (assoc key (cdr table))))
          (or record
              (let ((new-rear (cons (list key)
                                    (cdr table))))
                ;;create a new subtable and return it
                (set-cdr! table new-rear)
                (car new-rear)))))
      (set-cdr! (general-lookup sub-insert local-table key-list)
                value)
      'ok)

    (define (print) 
      (define (indent tabs)
        (if (> tabs 0)
            (begin (display "    ")
                   (indent (- tabs 1)))))
  
      (define (print-record rec level) 
        (indent level) 
        (display (car rec)) 
        (display ": ") 
        (if (list? rec) 
            (begin (newline) 
                   (print-table rec (+ 1 level))) 
            (begin (display (cdr rec)) 
                   (newline)))) 
              
      (define (print-table table level) 
        (if (null? (cdr table)) 
            (begin (display "-no entries-") 
                   (newline)) 
            (for-each (lambda (record) 
                        (print-record record level)) 
                      (cdr table)))) 
  
      (print-table local-table 0))
    
    (define (dispatch m)
      (cond ((eq? m 'lookup-proc) lookup)
            ((eq? m 'insert-proc!) insert!)
            ((eq? m 'print) print)
            (else (error "Unknown operation -- TABLE" m))))
    dispatch))

(define op-table (make-table))
(define put (op-table 'insert-proc!))
(define get (op-table 'lookup-proc))
((op-table 'print))

(put '(letters a) 97)
(put '(letters b) 98)
(put '(math +) 43)
(put '(math -) 45)
(put '(math *) 42)
(put '(greek majiscule ^) 923)
(put '(min) 42)
(put '(max) 955)
(get '(min))

((op-table 'print))